import moment from 'moment';
import G6 from '@antv/g6';
// 原因类型
export let reasionTypes = [
    {
        id:'reas_1',
        value:'我是第一个原因',
        color:'#67F9D8'
    },
    {
        id:'reas_2',
        value:'我是第二个原因',
        color:'#FFE434'
    },
    {
        id:'reas_3',
        value:'我是第三个原因',
        color:'#56A3F1'
    },
];
// 关系类型
let relationTypes = [
    {
        id:'1',
        value:'因果',
        color:'#f00'
    },
    {
        id:'2',
        value:'支撑',
        color:'#00f'
    },
    {
        id:'3',
        value:'促进',
        color:'#0ff'
    },
    {
        id:'4',
        value:'递进',
        color:'#f0f'
    },
    {
        id:'5',
        value:'顺承',
        color:'#ccc'
    }
]
// 模拟接口数据
export function createMockData(timeCount,step = 10){
    let data = [];
    // let timeCount = 10;
    let weight = 1;
    let timeState = Date.now();
    let mockDataItem = {
        id:'1',
        type:'time',
        eventTime:'2021-01-01',
        events:[]
    };
    let eventItem = {
        id:'1',
        type:'event',
        abstract:'',
        containt:'我是内容，我是内容，我是内容，我是内容',
        reasonTypeId:'reas_1'
    }
    let reasonMap = new Map();
    let eventsList = [];
    for(var i=0;i<timeCount;i++){
        let level = Math.ceil(i / step); // 懒加载时使用，默认加载条数，保留字段
        let column = i + 1;  // 列数
        let mockDataItem = {};
        mockDataItem.id = `time_${i+1}`;
        mockDataItem.eventTime = moment(timeState-i*10).format('YYYY-MM-DD HH:MM:SS');
        mockDataItem.type = 'time';
        mockDataItem.events = [];
        mockDataItem.level = level;
        mockDataItem.column = column;
        let eventCount = Math.ceil(Math.random() * 3);
        for(let j=0;j<eventCount;j++){
            let eventItem = {};
            eventItem.id = `event_${i}_${j}`;
            eventItem.level = level;
            eventItem.column = column;
            eventItem.weight = weight++;  // 事件顺序，由小到大表示顺承关系
            eventItem.type = 'event';
            eventItem.abstract = '摘要：“我的钱分散在好多个篮子里,结果涨时不挣钱,跌时一起跌。”一位投资者很无奈地表示。上周全球金融市场经历了历史性时刻,不仅全球股票市场出现调整,包括美债、黄金等传统意义上具备避险属性的资产也都出现大幅波动。';
            eventItem.containt = '内容：我“我的钱分散在好多个篮子里,结果涨时不挣钱,跌时一起跌。”一位投资者很无奈地表示。上周全球金融市场经历了历史性时刻,不仅全球股票市场出现调整,包括美债、黄金等传统意义上具备避险属性的资产也都出现大幅波动。dfahkue';
            eventItem.reasonTypeId = reasionTypes[Math.floor(Math.random() * 3)];
            eventItem.target = [];
            // if(i==0 && j==0){
            //     eventItem.target.push({
            //         id : `event_${9}_${0}`,
            //         relationship:relationTypes[0]
            //     })
            // }else if(i == 9 && j==0){
            //     eventItem.target.push({
            //         id : `event_${0}_${0}`,
            //         relationship:relationTypes[1]
            //     })
            // }else if(Math.random() > 0.5){
            //     if(Math.random() > 0.5){
            //         let fir = Math.ceil(Math.random() * timeCount);
            //         let sec = Math.ceil(Math.random() * 3);
            //         eventItem.target.push({
            //             id : `event_${fir}_${sec}`,
            //             relationship:relationTypes[Math.ceil(Math.random() * 4)]
            //         })
            //     }
            // }
            if(reasonMap.has(eventItem.reasonTypeId)){
                reasonMap.get(eventItem.reasonTypeId).push(eventItem)
            }else{
                reasonMap.set(eventItem.reasonTypeId,[eventItem])
            }
            eventsList.push(eventItem);
            mockDataItem.events.push(eventItem)
        }
        data.push(mockDataItem);
    }
    reasonMap.forEach((list,key)=>{
        list.reverse().reduce((prev,current)=>{
            prev.target.push({
                id:current.id,
                relationship:relationTypes[Math.ceil(Math.random() * 4)]
            });
            return current;
        })
    })
    return data;
}
// 配置文件
function sizeConfig(step){
    // 默认是step<60
    let eventNodeConfig = {
        style:{
            width:30,
            height:15,
            lineWidth: 0.5,
            radius:2
        },
        anchorPoints: [
            [0.5, 0],
            [1, 0.5],
            [0.5, 1],
            [0, 0.5]
          ],
        labelCfg: {
            position:'top',
            offset:0,
            style: {
                fill: '#495057',
                fontSize: 2,
            },
        }
    };
    let timeNodeConfig = {
        size:[2,2],
        labelCfg: {
            position:'bottom',
            offset:4,
            style:{
                fontSize:4
            },
            icon:{
                show:true,
                width:2,
                height:2
            }
        }
    };
    if(step >= 60 && step < 90){
        eventNodeConfig.style.width = 45;
        eventNodeConfig.style.height = 30;
        eventNodeConfig.labelCfg.style.fontSize = 4;
        timeNodeConfig.size = [3,3];
        timeNodeConfig.labelCfg.style.fontSize = 5;
        timeNodeConfig.labelCfg.offset = 6;
    }else if(step >= 90 && step < 120){
        eventNodeConfig.style.width = 60;
        eventNodeConfig.style.height = 45;
        eventNodeConfig.labelCfg.style.fontSize = 6;
        timeNodeConfig.size = [5,5];
        timeNodeConfig.labelCfg.style.fontSize = 6;
        timeNodeConfig.labelCfg.offset = 10;
    }else if(step >= 120){
        eventNodeConfig.style.width = 75
        eventNodeConfig.style.height = 60;
        eventNodeConfig.labelCfg.style.fontSize = 6;
        timeNodeConfig.size = [5,5];
        timeNodeConfig.labelCfg.style.fontSize = 6;
        timeNodeConfig.labelCfg.offset = 10;
    };
    return {
        eventNodeConfig,
        timeNodeConfig
    }
}
// 单行文字超长时用省略号替换
/**
 * @description: 
 * @param {*} str       需要转换文本
 * @param {*} maxWidth  单行最大长度
 * @param {*} fontSize  字体大小
 * @return {*}
 */
export function fittingStringByEllopsis(str, maxWidth, fontSize){
    const ellipsis = "...";
    const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
    let currentWidth = 0;
    let res = str;
    const pattern = new RegExp("[\u4E00-\u9FA5]+"); // distinguish the Chinese charactors and letters
    str.split("").forEach((letter, i) => {
      if (currentWidth > maxWidth - ellipsisLength) return;
      if (pattern.test(letter)) {
        // Chinese charactors
        currentWidth += fontSize;
      } else {
        // get the width of single letter according to the fontSize
        currentWidth += G6.Util.getLetterWidth(letter, fontSize);
      }
      if (currentWidth > maxWidth - ellipsisLength) {
        res = `${str.substr(0, i)}${ellipsis}`;
      }
    });
    return res;
  };
  // 多行文字高度超出边框省略
/**
 * @description: 
 * @param {*} str        需要转换的文本
 * @param {*} maxWidth   单行最大长度
 * @param {*} maxHeight  最大高度
 * @param {*} fontSize   字体大小
 * @return {*}
 */
export function fittingString(str, maxWidth, maxHeight, fontSize){
    let currentWidth = 0;
    let currentHeight = 0;
    // let res = '';
    let res = [];
    let isCut = false;
    const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
    let cutOutIndexs = []; // 换行的索引
    str.split('').forEach((letter, i) => {
        if (currentWidth > maxWidth) return;
        if (pattern.test(letter)) {
            // Chinese charactors
            currentWidth += fontSize;
        } else {
            // get the width of single letter according to the fontSize
            currentWidth += G6.Util.getLetterWidth(letter, fontSize);
            // console.log(G6.Util.getLetterHeight(letter,fontSize))
        }
        if(currentWidth >= maxWidth){
            currentWidth = 0;
            cutOutIndexs.push(i);
        }
    });
    
    // 多行时
    if(cutOutIndexs.length){
        cutOutIndexs.reduce((prevIndex,curIndex,index)=>{
            currentHeight += fontSize;
            if(currentHeight <= maxHeight){
                res.push(str.substring(prevIndex,curIndex));
                if(index === cutOutIndexs.length - 1 && index < str.length - 1){
                    if(currentHeight + fontSize < maxHeight){
                        res.push(str.substr(curIndex));
                    }else{
                        let lastLineStr = fittingStringByEllopsis(res[res.length-1],maxWidth,fontSize);
                        console.log(lastLineStr)
                        res.pop();
                        res.push(lastLineStr)
                    }
                }
            }else if(!isCut){
                isCut = true;
                let lastLineStr = fittingStringByEllopsis(res[res.length-1],maxWidth,fontSize);
                res.pop();
                res.push(lastLineStr)
            }
            return curIndex;
        },0);
    }else{
    // 单行时
        res = [str];
    }
    return res.join('\n');
  };

// 创建时间节点
/**
 * @description: 
 * @param {*} width   canvas画布剩余宽度
 * @param {*} height  canvas画布高度
 * @param {*} data    新增节点列表
 * @param {*} step    节点间剧
 * @return {*}
 */
function createTimeNodes(width,height,data,step,timeNodeConfig){
    let timeNodes = []; // 时间节点
    for(let i=0;i<data.length;i++){
        let timeItem = Object.assign({},timeNodeConfig);
        timeItem.id = data[i].id;
        timeItem.label = data[i].eventTime;
        timeItem.level = data[i].level;
        timeItem.column = data[i].column;
        timeItem.x = width - step * (i + 1);
        timeItem.y = height - 100;
        data[i].x = timeItem.x;  // 保留当前时间节点的x和y坐标，供创建事件节点使用。
        data[i].y = timeItem.y;
        timeItem.type = 'time-node';
        if(i === data.length-1){
            timeItem.Madd = true;
            timeItem.icon = {
                show:true,
                width:2,
                height:2,
                text:'i'
            }
        }else{
            timeItem.icon = {}
        }
        timeNodes.push(timeItem);
    }
    return timeNodes;
}

// 创建时间连线
/**
 * @description: 
 * @param {*} timeNodes  时间节点列表
 * @return {*}
 */
function createTimeLines(timeNodes){
    let timeEdges = [];
    timeNodes.reduce((prev,current)=>{
        let edgeItem = {
            style:{
                lineWidth:0.5
            }
        };
        if(prev){
            edgeItem.id = `${prev.id}-${current.id}`;
            edgeItem.source = prev.id;
            edgeItem.target = current.id;
            edgeItem.level = prev.level;
            edgeItem.sourceColumn = prev.column;
            edgeItem.targetColumn = current.column;
            edgeItem.edgeType="horizontal-timeline"
            timeEdges.push(edgeItem);
        }
        return current;
    },null);
    return timeEdges;
}

// 创建事件节点和竖向连线
/**
 * @description: 
 * @param {*} data 原始数据
 * @param {*} step 相邻两时间节点间距
 * @param {*} eventNodeConfig 默认事件节点配置
 * @return {*}
 */
function createEventNodesAndVerticalEdges(data,step,eventNodeConfig){
    let eventNodes = []; // 所有的事件节点列表
    let verticalEdges = [];  // 所有的竖向线
    let levelStep = step;  // 相邻时间节点间距
    let relationships = new Map(); // 非默认顺承关系的其他关系 key:node1Id-node2Id,value:{source:node1Item,target:node2Item,relationship:'因果',reverseRelationship?:'支撑',twoWay:boolean}
    let arrowEdges = []; // 所有的关系连线列表
    let nodesMap = new Map(); // 所有事件节点，key:nodeId,value:nodeItem
    let nodesWithTargetMap = new Map(); // 所有存在target的节点 key:currentId,value:[target1Id,target2Id...]
    for(let i=0;i<data.length;i++){
        let events = data[i].events;
        if(events.length){
            for(let j=0;j<events.length;j++){
                let row = j + 1;
                let eventNodeItem = Object.assign({},eventNodeConfig);
                eventNodeItem.type = 'event-node';
                eventNodeItem.id = events[j].id;
                eventNodeItem.containt = events[j].containt;
                eventNodeItem.abstract = events[j].abstract;
                eventNodeItem.reasonType = events[j].reasonTypeId;
                eventNodeItem.level = events[j].level;
                eventNodeItem.column = events[j].column;
                eventNodeItem.row = row;
                eventNodeItem.weight = events[j].weight;
                eventNodeItem.x = data[i].x;
                eventNodeItem.y = data[i].y - levelStep * (j+1);
                eventNodeItem.time = data[i].eventTime;
                eventNodeItem.timeId = data[i].id;
                eventNodeItem.step = levelStep;
                eventNodeItem.target = events[j].target;
                eventNodes.push(eventNodeItem);
                nodesMap.set(eventNodeItem.id,eventNodeItem);
                if(!events[j-1]){
                    let verticalEdgeItem = {
                        style:{
                            lineWidth:0.5
                        }
                    };
                    // verticalEdgeItem.style.lineWidth = 1;
                    verticalEdges.edgeType = 'vertical-timeline';
                    verticalEdgeItem.target = events[j].id;
                    // verticalEdgeItem.source = events[j-1] ? events[j-1].id : data[i].id;
                    verticalEdgeItem.source = data[i].id;
                    verticalEdgeItem.id = `${verticalEdgeItem.source}-${verticalEdgeItem.target}`;
                    verticalEdgeItem.level = events[j].level;
                    verticalEdgeItem.column = events[j].column;
                    // verticalEdgeItem.style.endArrow = events[j-1] ? true : false;
                    verticalEdges.push(verticalEdgeItem);
                }
                if(eventNodeItem.target.length){
                    let currentId = eventNodeItem.id;
                    let target = eventNodeItem.target;
                    nodesWithTargetMap.set(currentId,target);
                }
            }
        }
    }
    // 添加非顺承关系连线
    nodesWithTargetMap.forEach((target,currentId)=>{
        target.forEach(item=>{
            let targetId = item.id;
            let source = nodesMap.get(currentId);
            let target = nodesMap.get(targetId);
            if(source && target){
                let sourceWeight = nodesMap.get(currentId).weight;
                let targetWeight = nodesMap.get(targetId).weight;
                let mapKey = `${currentId}-${targetId}`;
                let mapValue = {
                    sourceId:currentId,
                    targetId:targetId,
                    relationship:sourceWeight > targetWeight ? item.relationship : undefined,
                    reverseRelationship:targetWeight > sourceWeight ? item.relationship : undefined,
                    twoWay:false
                }
                relationships.set(mapKey,mapValue);
            }
        })
    })
    // 添加所有节点顺承关系
    // 顺承关系是否是默认的? ? ?如果是，前端生成还是后端生成，当前默认前端生成。
    eventNodes.reduce((prev,current)=>{
        if(prev){
            let mapKey = `${current.id}-${prev.id}`;
            let mapValue = {
                sourceId:current.id,
                targetId:prev.id,
                relationship:relationTypes[4],
                twoWay:false
            }
            // 当relationships中没有当前关系时，添加顺承关系，当有关系时默认使用接口返回的关系
            if(!relationships.has(mapKey)){
                relationships.set(mapKey,mapValue);
            }
        }
        return current;
    })
    // 合并双向关系
    relationships.forEach((value,key)=>{
        let reverseKey = key.replace(/(.*)-(.*)/,'$2_$1');
        if(relationships.has(reverseKey)){
            let reverseValue = relationships.get(reverseKey);
            if(value.relationship){
                value.reverseRelationship = reverseValue.reverseRelationship;
            }else{
                value.relationship = reverseValue.relationship
            }
            value.twoWay = true;
            relationships.delete(reverseKey);
        }
        let {sourceId,targetId,relationship,reverseRelationship,twoWay} = value;
        let source = nodesMap.get(sourceId);
        let target = nodesMap.get(targetId);
        let arrowEdge = defineArrowEdge(source,target,twoWay,relationship,reverseRelationship);
        arrowEdge && arrowEdges.push(arrowEdge);
    });
    return {eventNodes,verticalEdges,arrowEdges};
}

// 定义关系连接线
/**
 * @description: 
 * @param {*} sourceNode  连接线起始节点
 * @param {*} targetNode  连接线终止节点
 * @param {*} isTowWay    是否是双箭头
 * @param {*} relationship 由左指向右的关系，标在连线上方
 * @param {*} reverseRelationship 由右指向左关系，标在连线下方
 * @return {*}
 */
function defineArrowEdge(sourceNode,targetNode,isTowWay=false,relationship=undefined,reverseRelationship=undefined){
    if(!sourceNode || !targetNode){
        return;
    }
    let arrowEdge = {};
    arrowEdge.type = 'event-arrow';
    arrowEdge.source = sourceNode.id;
    arrowEdge.target = targetNode.id;
    arrowEdge.id = `${arrowEdge.source}-${arrowEdge.target}`;
    arrowEdge.level = sourceNode.level;
    arrowEdge.offset = (sourceNode.step - sourceNode.style.width)/3;
    arrowEdge.eventNodeWidth = sourceNode.style.width;
    arrowEdge.eventNodeHeight = sourceNode.style.height;
    arrowEdge.step = sourceNode.step;
    arrowEdge.sourceColumn = sourceNode.column;  // 由
    arrowEdge.targetColumn = targetNode.column;
    arrowEdge.sourceRow = sourceNode.row;
    arrowEdge.targetRow = targetNode.row;
    arrowEdge.sourceWeight = sourceNode.weight;
    arrowEdge.targetWeight = targetNode.weight;
    let { sourceAnchor, targetAnchor } = calculateAnchor(arrowEdge);
    arrowEdge.sourceAnchor = sourceAnchor;
    arrowEdge.targetAnchor = targetAnchor;
    arrowEdge.isTowWay = isTowWay;
    arrowEdge.relationship = relationship;
    arrowEdge.reverseRelationship = reverseRelationship;
    arrowEdge.fontSize = sourceNode.labelCfg.style.fontSize;
    return arrowEdge;
}
// 定义连线对应连接点
/**
 * @description: 
 * @param {*} edge 自定义连接线对象
 * @return {*}
 */
function calculateAnchor(edge){
    let {sourceColumn,targetColumn,sourceRow,targetRow,sourceWeight,targetWeight} = edge;
    let sourceAnchor,targetAnchor;
    if((sourceColumn === targetColumn || sourceRow === targetRow) && Math.abs(sourceWeight - targetWeight) === 1){ 
        // 指相邻的两个事件间连线
        return {sourceAnchor,targetAnchor};
    }else if(Math.abs(sourceColumn - targetColumn) === 1){
        // 相邻两列事件连线
        sourceAnchor = sourceColumn > targetColumn ? 1 : 3;
        targetAnchor = targetColumn > sourceColumn ? 1 : 3;
        return {sourceAnchor,targetAnchor};
    }else if(sourceRow === targetRow && Math.abs(sourceWeight - targetWeight) > 1){
        // 行数相同但不相邻
        sourceAnchor = 2;
        targetAnchor = 2;
        return {sourceAnchor,targetAnchor};
    }else if(sourceColumn === targetColumn && Math.abs(sourceWeight - targetWeight) > 1){
        console.log('dfjie')
        // 列数相同但不相邻
        sourceAnchor = 1;
        targetAnchor = 1;
        return {sourceAnchor,targetAnchor};
    }else{
        // 行列都不相同
        sourceAnchor = sourceColumn > targetColumn ? 1 : 3;
        targetAnchor = sourceColumn > targetColumn ? 3 : 1;
        return {sourceAnchor,targetAnchor};
    }
}

/**
 * @description: 
 * @param {*} width // 画布总宽
 * @param {*} height // 画布总高
 * @param {*} showNums // 已展示时间节点个数
 * @param {*} addDatas  // 新增时间节点数据
 * @return {*}
 */    
export function stepCreateNodes(width,height,showNums,addDatas){
    let nums = 20;       // 最多展示时间节点个数
    let padding = 50;    // 画布左右两侧留白
    let step = Math.floor((width - padding * 2) / nums);
    // let step = 100;
    // console.log('step',step)
    let remainWidth = width - showNums * step; // 画布剩余宽度
    let { eventNodeConfig, timeNodeConfig } = sizeConfig(step);
    let timeNodes = createTimeNodes(remainWidth,height,addDatas,step,timeNodeConfig);  // 新增时间节点列表
    let timeEdges = createTimeLines(timeNodes);  // 新增时间轴连线
    let { eventNodes,verticalEdges,arrowEdges } = createEventNodesAndVerticalEdges(addDatas,step,eventNodeConfig); // 新增事件节点和竖向连线
    // console.log('timeNodes',timeNodes)
    // console.log('timeEdges',timeEdges)
    // console.log('eventNodes',eventNodes)
    // console.log('verticalEdges',verticalEdges)
    // console.log('arrowEdges',arrowEdges)
    let data = {
        nodes:[
            ...timeNodes,
            ...eventNodes
        ],
        edges:[
            ...timeEdges,
            ...verticalEdges,
            ...arrowEdges,
        ]
    }
    return data;
    
    
}
